﻿//--------------------------------------------------------------------------
// 
//  Copyright (c) Chili Software.  All rights reserved. 
// 
//  File: ConcurrencyException.cs
//
//  Description: Thrown if a concurrency problems happens.
// 
//--------------------------------------------------------------------------

using System;
using System.Runtime.Serialization;
using System.Security.Permissions;

namespace Chili.Opf3.Concurrency
{
	/// <summary>
	/// Exception is thrown if a concurrency problem happens.
	/// </summary>
	/// <remarks>
	/// This exception is thrown by the <see cref="Opf3.ObjectContext">ObjectContext</see> or
	/// <see cref="Opf3.Concurrency.IConcurrencyManager">IConcurrencyManager</see> if a concurrency
	/// problem happened. It should be catched on each save process in your application to notice 
	/// the user that a concurrency problem happend.
	/// </remarks>
	[Serializable]
	public sealed class ConcurrencyException : Exception
	{
		private object _persistent;
		private object _storagePersistent;

		/// <summary>
		/// Creates a new instance of the <see cref="ConcurrencyException">ConcurrencyException Class</see>.
		/// </summary>
		/// <param name="persistent">The persistent object that caused the exception.</param>
		/// <param name="storagePersistent">The persistent object that has been reloaded from the storage to check for concurrency problems.</param>
		public ConcurrencyException(object persistent, object storagePersistent) : base()
		{
			_persistent = persistent;
			_storagePersistent = storagePersistent;
		}

		/// <summary>
		/// Creates a new instance of the <see cref="ConcurrencyException">ConcurrencyException Class</see>.
		/// </summary>
		/// <param name="message">A message that describes the current exception.</param>
		/// <param name="persistent">The persistent object that caused the exception.</param>
		/// <param name="storagePersistent">The persistent object that has been reloaded from the storage to check for concurrency problems.</param>
		public ConcurrencyException(string message, object persistent, object storagePersistent)
			: base(message)
		{
			_persistent = persistent;
			_storagePersistent = storagePersistent;
		}

		/// <summary>
		/// Creates a new instance of the <see cref="ConcurrencyException">ConcurrencyException Class</see>.
		/// </summary>
		/// <param name="message">A message that describes the current exception.</param>
		/// <param name="persistent">The persistent object that caused the exception.</param>
		/// <param name="inner">The exception that caused the current exception.</param>
		/// <param name="storagePersistent">The persistent object that has been reloaded from the storage to check for concurrency problems.</param>
		public ConcurrencyException(string message, object persistent, object storagePersistent, Exception inner) 
			: base(message, inner) 
		{
			_persistent = persistent;
			_storagePersistent = storagePersistent;
		}

		/// <summary>
		/// Creates a new instance of the
		/// <see cref="ConcurrencyException">ConcurrencyException Class</see>.
		/// </summary>
		private ConcurrencyException(SerializationInfo info, StreamingContext context) : base(info, context)
		{
			_persistent = info.GetValue("persistent", typeof(object));
			_storagePersistent = info.GetValue("storagePersistent", typeof(object));
		}

		/// <summary>
		/// Restores the objects data after serialization.
		/// </summary>
		[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
		public override void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			base.GetObjectData(info, context);
			info.AddValue("persistent", _persistent);
			info.AddValue("storagePersistent", _storagePersistent);
		}

		/// <summary>
		/// Returns the persistent object that caused the exception.
		/// </summary>
		public object Persistent
		{
			get { return _persistent; }
			private set { _persistent = value; }
		}

		/// <summary>
		/// Return the persistent object that has been reloaded from the storage to check for concurrency problems.
		/// Or null if the persistent hasn't been found in the storage.
		/// </summary>
		public object StoragePersistent
		{
			get { return _storagePersistent; }
			private set { _storagePersistent = value; }
		}
	}
}
